package com.tianji.learning.service.impl;

import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.checkerframework.framework.qual.EnsuresQualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.sql.Date;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author yp
 * @since 2024-07-31
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
    private final StringRedisTemplate redisTemplate;

    private final UserClient userClient;

    /**
     * 根据赛季查询积分排行榜
     *
     * @param query
     * @return
     */
    @Override
    public PointsBoardVO queryPointBoardBySesson(PointsBoardQuery query) {
        //1.判断查询的是当前赛季还是历史赛季
        Long season = query.getSeason();
        boolean isCurrent = season == null || season == 0;
        //2.查询当前用户的榜单（积分和排名）
        LocalDateTime now = LocalDateTime.now();
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        PointsBoard myPointBoard = isCurrent ? queryMyCurrentBoard(key) : queryHistoryBoard(query);
        //3.查询排行榜
        List<PointsBoard> pointsBoardList = isCurrent ? queryCurrentBoardList(key, query.getPageNo(), query.getPageSize()) : queryHistoryBoardList(query);
        //封装PointBoardVo
        PointsBoardVO vo = new PointsBoardVO();
        //4.1封装我的积分和排名
        if (myPointBoard != null) {
            vo.setPoints(myPointBoard.getPoints());
            vo.setRank(myPointBoard.getRank());
        }
        if (CollUtils.isEmpty(pointsBoardList)) {
            return vo;
        }
        // 4.2.1根据用户id查询用户信息‘
        Set<Long> userIds = pointsBoardList.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        Map<Long, UserDTO> userMap = new HashMap<>();
        if (CollUtils.isNotEmpty(userIds)) {
            List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
            if (CollUtils.isNotEmpty(userDTOS)) {
                userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
            }
        }
        // 4.2.2封装成List<PointsBoardItemVO> 每次遍历就封装一个PointBoardItemVO对象
        List<PointsBoardItemVO> pointsBoardItemVOList = new ArrayList<>();
        for (PointsBoard pointsBoard : pointsBoardList) {
            PointsBoardItemVO itemVO = new PointsBoardItemVO();
            Long userId = pointsBoard.getUserId();
            Integer points = pointsBoard.getPoints();
            Integer rank = pointsBoard.getRank();
            if (userId == null || points == null || rank == null) {
                continue;
            }
            UserDTO userDTO = userMap.get(userId);
            if (userDTO != null) {
                itemVO.setName(userDTO.getName());
            }
            itemVO.setRank(rank);
            itemVO.setPoints(points);
            pointsBoardItemVOList.add(itemVO);
        }
        vo.setBoardList(pointsBoardItemVOList);
        return vo;
    }


    /**
     * 创建表名
     *
     * @param tableName
     */
    @Override
    public void createPointBoardTableBySesson(String tableName) {
        getBaseMapper().createPointBoardTableBySesson(tableName);
    }


    /**
     * 查询实时的排行榜
     *
     * @param key
     * @param pageNo
     * @param pageSize
     * @return
     */
    private List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {

        //1.计算start 和 end
        int start = (pageNo - 1) * pageSize;
        int end = start + pageSize - 1;
        //2.从Redis查询 ZREVRANGE Key start stop [WITHSCORES]
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        if (CollUtils.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }
        //3.封装List<PointsBoard>
        List<PointsBoard> pointsBoardLists = new ArrayList<>();
        int rank = start + 1;
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            //每遍历一次对象返回一个PointsBoard对象
            PointsBoard po = new PointsBoard();
            String userId = tuple.getValue();
            Double score = tuple.getScore();
            if (userId == null || score == null) {
                continue;
            }

            //封装
            po.setUserId(Long.valueOf(userId));
            po.setPoints(score.intValue());
            po.setRank(rank);
            rank++;
            pointsBoardLists.add(po);
        }
        return pointsBoardLists;
    }


    /**
     * 查询历史赛季的榜单（当前赛季赛季）
     *
     * @param key
     * @return
     */
    private PointsBoard queryMyCurrentBoard(String key) {
        Long userId = UserContext.getUser();
        //1.查询我的排名 ZREVRANK key member
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());
        //2.查询参数 ZScore key member
        Double score = redisTemplate.opsForZSet().score(key, userId.toString());
        PointsBoard myBoard = new PointsBoard();
        myBoard.setRank(rank != null ? rank.intValue() + 1 : 0);
        myBoard.setPoints(score != null ? score.intValue() : 0);
        return myBoard;
    }

    /**
     * 查询历史赛季的榜单（历史赛季）
     *
     * @param query
     * @return
     */
    private PointsBoard queryHistoryBoard(PointsBoardQuery query) {
        return null;
    }

    /**
     * 查询历史的排行榜
     *
     * @param query
     * @return
     */
    private List<PointsBoard> queryHistoryBoardList(PointsBoardQuery query) {
        return null;
    }

}
